package ar.edu.uba.fi.jmit.aspecter;

import java.lang.reflect.InvocationTargetException;

import javassist.ClassPool;
import javassist.CtClass;
import ar.edu.uba.fi.jmit.aspecter.core.injector.Injector;
import ar.edu.uba.fi.jmit.aspecter.testUtils.ExceptionConstructorInjector;
import ar.edu.uba.fi.jmit.aspecter.testUtils.TestUtils;

public class ConstructorInjectorTestCase extends AspecterTestCase {

	public void testInjectAll() {
		try {
			Injector injector = new ExceptionConstructorInjector();
			CtClass ctClazz = ClassPool.getDefault().getAndRename("ar.edu.uba.fi.jmit.aspecter.testUtils.PointTest2", getNextClassName());
			injector.inject(ctClazz);
			Class<?> clazz = ctClazz.toClass();
			
			try{
				clazz.newInstance();
				fail("Exception should be thrown!");
			}catch(RuntimeException e) {
				assertEquals("injected!", e.getMessage());
			}
			
			try{
				TestUtils.newInstance(clazz, 1);
				fail("Exception should be thrown!");
			}catch(InvocationTargetException e) {
				//here should be wrapped the runtime exception
				assertEquals(RuntimeException.class, e.getTargetException().getClass());
				assertEquals("injected!", e.getTargetException().getMessage());
			}
			
			try{
				TestUtils.newInstance(clazz, 1, 2);
				fail("Exception should be thrown!");
			}catch(InvocationTargetException e) {
				//here should be wrapped the runtime exception
				assertEquals(RuntimeException.class, e.getTargetException().getClass());
				assertEquals("injected!", e.getTargetException().getMessage());
			}
			
		} catch (Exception e) {
			fail(e);
		} 
	}
	
	public void testCheckParameters() {
		try {
			ExceptionConstructorInjector injector = new ExceptionConstructorInjector();
			injector.addParameterTypes(new Class<?>[]{});//want to inject on empty constructor
			CtClass ctClazz = ClassPool.getDefault().getAndRename("ar.edu.uba.fi.jmit.aspecter.testUtils.PointTest2", getNextClassName());
			injector.inject(ctClazz);
			Class<?> clazz = ctClazz.toClass();
			
			try{
				clazz.newInstance();
				fail("Exception should be thrown!");
			}catch(RuntimeException e) {
				assertEquals("injected!", e.getMessage());
			}
			
			try{
				TestUtils.newInstance(clazz, 1);
			}catch(RuntimeException e) {
				fail(e);
			}
			
			try{
				TestUtils.newInstance(clazz, 1, 2);
			}catch(RuntimeException e) {
				fail(e);
			}
			
		} catch (Exception e) {
			fail(e);
		} 
	}
	
	public void testCheckParameters2() {
		try {
			ExceptionConstructorInjector injector = new ExceptionConstructorInjector();
			injector.addParameterTypes(new Class<?>[]{int.class});
			CtClass ctClazz = ClassPool.getDefault().getAndRename("ar.edu.uba.fi.jmit.aspecter.testUtils.PointTest2", getNextClassName());
			injector.inject(ctClazz);
			Class<?> clazz = ctClazz.toClass();
			
			try{
				clazz.newInstance();
				fail("Exception should be thrown!");//empty constructor calls the injected constructor
			}catch(RuntimeException e) {
				assertEquals("injected!", e.getMessage());
			}
			
			try{
				TestUtils.newInstance(clazz, 1);
				fail("Exception should be thrown!");
			}catch(InvocationTargetException e) {
				//here should be wrapped the runtime exception
				assertEquals(RuntimeException.class, e.getTargetException().getClass());
				assertEquals("injected!", e.getTargetException().getMessage());
			}
			
			try{
				TestUtils.newInstance(clazz, 1, 2);
			}catch(InvocationTargetException e) {
				//here should be wrapped the runtime exception
				assertEquals(RuntimeException.class, e.getTargetException().getClass());
				assertEquals("injected!", e.getTargetException().getMessage());
			}
			
		} catch (Exception e) {
			fail(e);
		} 
	}
	
	public void testInjectDefaultConstructor() {
		try {
			Injector injector = new ExceptionConstructorInjector();
			CtClass ctClazz = TestUtils.getPointCopyClassForTest();
			injector.inject(ctClazz);
			Class<?> clazz = ctClazz.toClass();
			
			try{
				clazz.newInstance();
				fail("Exception should be thrown!");//empty constructor calls the injected constructor
			}catch(RuntimeException e) {
				assertEquals("injected!", e.getMessage());
			}
		} catch (Exception e) {
			fail(e);
		} 
	}
}
